#include "game_engine.h"

GameEngine::GameEngine()
    : m_white_board(0),
      m_black_board(1),
      m_curr_board(&m_white_board),
      m_opp_board(&m_black_board),
      m_current_player(0),
      m_curr_row(0),
      m_curr_column(0),
      m_valid_move(false),
      m_num_moves(-1),
      m_white_score(0),
      m_black_score(0),
      m_winner(-1),
      m_finished(false)
{

}

void GameEngine::set_board(ReversiBoard *board, player p){
    if ( p == WHITE_PLAYER){
        m_white_board = *board;
        m_white_score = board->get_score();
    }
    if ( p == BLACK_PLAYER){
        m_black_board = *board;
        m_black_score = board->get_score();
    }
}

void GameEngine::set_player(player p){
    if ( p == WHITE_PLAYER) {
        m_current_player = 0;
        set_curr_player();
    }
    if ( p == BLACK_PLAYER){
        m_current_player = 1;
        set_curr_player();
    }
}

void GameEngine::set_curr_player(){
    if(m_current_player == 0){
        m_curr_board = &m_white_board;
        m_opp_board = &m_black_board;
    }else{
        m_curr_board = &m_black_board;
        m_opp_board = &m_white_board;

    }
    m_white_score = m_white_board.get_score();
    m_black_score = m_black_board.get_score();
}

void GameEngine::set_board(ReversiBoard *black_board, ReversiBoard *white_board){
    if(m_current_player == 0){
        m_curr_board = white_board;
        m_opp_board = black_board;
    }else{
        m_curr_board = black_board;
        m_opp_board = white_board;

    }
    m_white_score = white_board->get_score();
    m_black_score = black_board->get_score();
}

void GameEngine::switch_players(){
    if(m_current_player == 0){
        m_current_player = 1;
    }else{
        m_current_player = 0;
    }
}

void GameEngine::check_valid_moves(){
    int top_row = m_curr_row;
    int bottom_row = m_curr_row;
    int left_column = m_curr_column;
    int right_column = m_curr_column;
    int left_top_row = m_curr_row;
    int right_top_row = m_curr_row;
    int left_top_column = m_curr_column;
    int right_top_column = m_curr_column;
    int left_bottom_row = m_curr_row;
    int right_bottom_row = m_curr_row;
    int left_bottom_column = m_curr_column;
    int right_bottom_column = m_curr_column;
    bool curr_piece;
    bool op_piece;
    m_valid_move = false;

    //LEFTMOST PIECE
    int i, j;
    //Collumn
    j = m_curr_column-1;
    //m_curr_row
    i = m_curr_row;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_column = j;
    }

    //RIGHTMOST PIECE
    //Collumn
    j = m_curr_column+1;
    //m_curr_row
    i = m_curr_row;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_column = j;
    }

    //UPMOST m_curr_row
    j = m_curr_column;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1))){
        m_valid_move = true;
        top_row = i;
    }

    //UPMOST m_curr_row
    j = m_curr_column;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1))){
        m_valid_move = true;
        bottom_row = i;
    }
    //TOP-LEFT m_curr_row AND m_curr_column
    j = m_curr_column-1;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1)) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_top_row = i;
        left_top_column = j;
    }

    //TOP-RIGHT m_curr_row AND m_curr_column
    j = m_curr_column+1;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1)) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_top_row = i;
        right_top_column = j;
    }

    //BOTTOM-LEFT m_curr_row AND m_curr_column
    j = m_curr_column-1;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1)) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_bottom_row = i;
        left_bottom_column = j;
    }

    //BOTTOM-RIGHT m_curr_row AND m_curr_column
    j = m_curr_column+1;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1)) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_bottom_row = i;
        right_bottom_column = j;
    }
}

int* GameEngine::get_move_limits(){
    int top_row = m_curr_row;
    int bottom_row = m_curr_row;
    int left_column = m_curr_column;
    int right_column = m_curr_column;
    int left_top_row = m_curr_row;
    int right_top_row = m_curr_row;
    int left_top_column = m_curr_column;
    int right_top_column = m_curr_column;
    int left_bottom_row = m_curr_row;
    int right_bottom_row = m_curr_row;
    int left_bottom_column = m_curr_column;
    int right_bottom_column = m_curr_column;
    bool curr_piece;
    bool op_piece;
    m_valid_move = false;

    //LEFTMOST PIECE
    int i, j;
    //Collumn
    j = m_curr_column-1;
    //m_curr_row
    i = m_curr_row;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_column = j;
    }

    //RIGHTMOST PIECE
    //Collumn
    j = m_curr_column+1;
    //m_curr_row
    i = m_curr_row;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_column = j;
    }

    //UPMOST m_curr_row
    j = m_curr_column;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1))){
        m_valid_move = true;
        top_row = i;
    }

    //UPMOST m_curr_row
    j = m_curr_column;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1))){
        m_valid_move = true;
        bottom_row = i;
    }
    //TOP-LEFT m_curr_row AND m_curr_column
    j = m_curr_column-1;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1)) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_top_row = i;
        left_top_column = j;
    }

    //TOP-RIGHT m_curr_row AND m_curr_column
    j = m_curr_column+1;
    i = m_curr_row-1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i--;
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row-1)) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_top_row = i;
        right_top_column = j;
    }

    //BOTTOM-LEFT m_curr_row AND m_curr_column
    j = m_curr_column-1;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        j--;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1)) && (j!=(m_curr_column-1))){
        m_valid_move = true;
        left_bottom_row = i;
        left_bottom_column = j;
    }

    //BOTTOM-RIGHT m_curr_row AND m_curr_column
    j = m_curr_column+1;
    i = m_curr_row+1;
    op_piece = m_opp_board->get_piece(i,j);
    while(op_piece){
        i++;
        j++;
        op_piece = m_opp_board->get_piece(i,j);
    }
    curr_piece = m_curr_board->get_piece(i,j);
    if((curr_piece) && (i!=(m_curr_row+1)) && (j!=(m_curr_column+1))){
        m_valid_move = true;
        right_bottom_row = i;
        right_bottom_column = j;
    }

    if(!m_valid_move){
        return NULL;
    }
    int *move_limits = new int[12];
    move_limits[0] = left_column;
    move_limits[1] = right_column;
    move_limits[2] = top_row;
    move_limits[3] = bottom_row;
    move_limits[4] = left_top_row;
    move_limits[5] = left_top_column;
    move_limits[6] = right_top_row;
    move_limits[7] = right_top_column;
    move_limits[8] = left_bottom_row;
    move_limits[9] = left_bottom_column;
    move_limits[10] = right_bottom_row;
    move_limits[11] = right_bottom_column;
    return move_limits;
}

void GameEngine::make_move(int* move_limits){

    int left_column = move_limits[0];
    int right_column = move_limits[1];
    int top_row = move_limits[2];
    int bottom_row = move_limits[3];
    int left_top_row = move_limits[4];
    int left_top_column = move_limits[5];
    int right_top_row = move_limits[6];
    int right_top_column = move_limits[7];
    int left_bottom_row = move_limits[8];
    int left_bottom_column = move_limits[9];
    int right_bottom_row = move_limits[10];
    int right_bottom_column = move_limits[11];

    int i;
    int j;

    //Left and Right
    i = m_curr_row;
    for(j = left_column+1; j<m_curr_column; j++){
        m_opp_board->set_piece(i,j,false);
        m_curr_board->set_piece(i,j,true);
    }
    for(j = right_column-1; j>m_curr_column; j--){
        m_opp_board->set_piece(i,j,false);
        m_curr_board->set_piece(i,j,true);
    }
    //Top and Bottom
    j = m_curr_column;
    for(i = m_curr_row-1; i > top_row; i--){
        m_opp_board->set_piece(i,j, false);
        m_curr_board->set_piece(i,j,true);
    }
    for(i = m_curr_row+1; i< bottom_row; i++){
        m_opp_board->set_piece(i,j,false);
        m_curr_board->set_piece(i,j,true);
    }
    //Top Left
    j = m_curr_column-1;
    i = m_curr_row-1;
    while((i > left_top_row) && (j > left_top_column)){
        m_opp_board->set_piece(i,j, false);
        m_curr_board->set_piece(i,j,true);
        i--;
        j--;
    }

    //Top Right
    j = m_curr_column+1;
    i = m_curr_row-1;
    while((i > right_top_row) && (j < right_top_column)){
        m_opp_board->set_piece(i,j, false);
        m_curr_board->set_piece(i,j,true);
        i--;
        j++;
    }

    //Bottom Left
    j = m_curr_column-1;
    i = m_curr_row+1;
    while((i < left_bottom_row) && (j > left_bottom_column)){
        m_opp_board->set_piece(i,j, false);
        m_curr_board->set_piece(i,j,true);
        i++;
        j--;
    }

    //Bottom Right
    j = m_curr_column+1;
    i = m_curr_row+1;
    while((i < right_bottom_row) && (j < right_bottom_column)){
        m_opp_board->set_piece(i,j, false);
        m_curr_board->set_piece(i,j,true);
        i++;
        j++;
    }

    m_curr_board->set_piece(m_curr_row,m_curr_column,true);

    delete [] move_limits;
    move_limits = NULL;
}

void GameEngine::verify_move(int column, int row){
    m_curr_row = row;
    m_curr_column = column;
    int *move_limits = NULL;
    if((!m_white_board.get_piece(row, column)) && !m_black_board.get_piece(row, column)){

        set_curr_player();
        move_limits = get_move_limits();
        if(m_num_moves == 0){
            switch_players();
            set_curr_player();
        }


        move_limits = get_move_limits();
        if(m_num_moves == 0){
            game_finished();

        }

        if(move_limits != NULL){
            make_move(move_limits);
            switch_players();
        }
    }
}

void GameEngine::teste_move(int column, int row){
    m_curr_row = row;
    m_curr_column = column;
    int *move_limits = NULL;
    if((!m_white_board.get_piece(row, column)) && !m_black_board.get_piece(row, column)){

        set_curr_player();
        move_limits = get_move_limits();
        if(m_num_moves == 0){
            switch_players();
            set_curr_player();
        }

        move_limits = get_move_limits();
        /*if(m_num_moves == 0){
            //game_finished();
            cout << "termined!" << endl;

        }*/

        if(move_limits != NULL){
            make_move(move_limits);
          //  switch_players();
        }
    }
}

ReversiBoard* GameEngine::get_board(int type){
    switch(type){
    case WHITE_PLAYER:
        return &m_white_board;
        break;
    case BLACK_PLAYER:
        return &m_black_board;
        break;
    }
    return NULL;
}

void GameEngine::get_available_moves(std::vector<int> & available_moves){
    int row;
    int column;
    set_curr_player();
    for(row = 0; row < 8; row++){
        for(column = 0; column < 8; column++){
            if(!m_curr_board->get_piece(row,column) && !m_opp_board->get_piece(row,column)){
                m_curr_row = row;
                m_curr_column = column;
                check_valid_moves();
                if(m_valid_move){
                    available_moves.push_back(column);
                    available_moves.push_back(row);
                }
            }
        }
    }
    m_num_moves = available_moves.size();
}

int GameEngine::get_current_player(){
    return m_current_player;
}

void GameEngine::game_finished(){
    if(m_white_score > m_black_score){
        m_winner = 0;
    }
    if(m_white_score < m_black_score){
        m_winner = 1;
    }
    if(m_white_score == m_black_score){
        m_winner = -1;
    }
    m_finished = true;
}

bool GameEngine::is_finished(){
    return m_finished;
}

int GameEngine::get_winner(){
    return m_winner;
}

int GameEngine::get_score(int player){
    switch(player){
    case 0:
        return m_white_score;
        break;
    case 1:
        return m_black_score;
        break;
    }
    return 0;
}
